package com.dcy.generate;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.dialect.Props;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.TemplateType;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.dcy.common.base.controller.DcyBaseController;
import com.dcy.common.base.mapper.DcyBaseMapper;
import com.dcy.common.base.service.DcyBaseService;
import com.dcy.generate.model.GenerModel;
import com.dcy.generate.model.PackageModel;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.List;
import java.util.Map;

/**
 * @Author：dcy
 * @Description: 基础版代码生成器
 * @Date: 2020/7/22 10:25
 */
@Slf4j
public class DcyGenerator {

    public static final String CREATE_IN_VO = "CreateInVO.java";
    public static final String UPDATE_IN_VO = "UpdateInVO.java";
    public static final String SEARCH_IN_VO = "SearchInVO.java";
    public static final String LIST_OUT_VO = "ListOutVO.java";
    public static final String CONVERT = "Convert.java";
    public static final String DAO = "Dao.java";
    public static final String VUE = "-manage.vue";
    public static final String VUE_JS = ".js";

    /**
     * RUN THIS
     */
    public static void main(String[] args) {
        final GenerModel generModel = Props.getProp("db.properties", CharsetUtil.UTF_8).toBean(GenerModel.class, "db");
        final PackageModel packageModel = Props.getProp("package.properties", CharsetUtil.UTF_8).toBean(PackageModel.class, "package");

        FastAutoGenerator.create(generModel.getUrl(), generModel.getUsername(), generModel.getPassword())
                .globalConfig(builder -> {
                    builder.author("dcy")
                            // 生成文件的输出目录
                            .outputDir(generModel.getPack())
                            // 是否打开输出目录
                            .disableOpenDir()
                            // 时间类型对应策略
                            .dateType(DateType.ONLY_DATE);
                })
                .packageConfig(builder -> {
                    builder.parent(packageModel.getParent())
                            .controller(packageModel.getController())
                            .entity(packageModel.getEntity())
                            .serviceImpl(packageModel.getServiceImpl())
                            .mapper(packageModel.getMapper())
                            .xml(packageModel.getXml());
                })
                .strategyConfig(builder -> {
                    builder
                            .addTablePrefix(generModel.getPrefix())
                            .addInclude(generModel.getTableName().split(StringPool.COMMA))

                            .entityBuilder()
                            .naming(NamingStrategy.underline_to_camel)
                            .enableLombok()
                            .enableChainModel()
                            .enableFileOverride()

                            .mapperBuilder()
                            .superClass(DcyBaseMapper.class)
                            .enableBaseColumnList()
                            .enableBaseResultMap()
                            .enableFileOverride()


                            .serviceBuilder()
                            .superServiceImplClass(DcyBaseService.class)
                            .formatServiceImplFileName("%sService")
                            .enableFileOverride()


                            .controllerBuilder()
                            .superClass(DcyBaseController.class)
                            .enableRestStyle()
                            .enableHyphenStyle()
                            .enableFileOverride();

                })
                .templateConfig(builder -> {
                    builder.disable(TemplateType.SERVICE)
                            .controller("/simple/controller.java")
                            .serviceImpl("/simple/serviceImpl.java")
                            .xml("/simple/mapper.xml");
                })
                .templateEngine(new FreemarkerTemplateEngine() {
                    @Override
                    protected void outputCustomFile(@NotNull List<CustomFile> customFiles, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
                        String entityName = tableInfo.getEntityName();
                        for (CustomFile customFile : customFiles) {
                            String fileName = String.format((customFile.getFilePath() + entityName + "%s"), customFile.getFileName());
                            if (VUE.equals(customFile.getFileName())) {
                                fileName = String.format((getConfigBuilder().getGlobalConfig().getOutputDir() + "vue/" + StrUtil.toSymbolCase(tableInfo.getEntityName(), '-') + "%s"), customFile.getFileName());
                            } else if (VUE_JS.equals(customFile.getFileName())) {
                                fileName = String.format((getConfigBuilder().getGlobalConfig().getOutputDir() + "vue/" + StrUtil.toSymbolCase(tableInfo.getEntityName(), '-') + "%s"), customFile.getFileName());
                            }
                            outputFile(new File(fileName), objectMap, customFile.getTemplatePath(), customFile.isFileOverride());
                        }
                    }
                })
                .injectionConfig(builder -> {
                    Map<String, Object> customMap = buildCustomMap(packageModel);
                    final List<CustomFile> customFileList = buildCustomFileList(generModel, packageModel);
                    builder.customMap(customMap)
                            .customFile(customFileList);
                })
                .execute();
    }

    /**
     * 构建自定义模板文件
     *
     * @param generModel
     * @param packageModel
     * @return
     */
    private static List<CustomFile> buildCustomFileList(GenerModel generModel, PackageModel packageModel) {
        // 包路径
        final String inputDtoPack = String.format("%s%s%s", packageModel.getParent(), StringPool.DOT, packageModel.getInputDto());
        final String outDtoPack = String.format("%s%s%s", packageModel.getParent(), StringPool.DOT, packageModel.getOutDto());
        final String dtoMapperPack = String.format("%s%s%s", packageModel.getParent(), StringPool.DOT, packageModel.getDtoMapper());
        final String daoPack = String.format("%s%s%s", packageModel.getParent(), StringPool.DOT, packageModel.getDao());

        // 文件夹路径
        final String inputDtoUrl = String.format("%s%s%s", generModel.getPack(), StrUtil.replace(inputDtoPack, StringPool.DOT, StringPool.SLASH), StringPool.SLASH);
        final String outputDtoUrl = String.format("%s%s%s", generModel.getPack(), StrUtil.replace(outDtoPack, StringPool.DOT, StringPool.SLASH), StringPool.SLASH);
        final String dtoMapperUrl = String.format("%s%s%s", generModel.getPack(), StrUtil.replace(dtoMapperPack, StringPool.DOT, StringPool.SLASH), StringPool.SLASH);
        final String daoUrl = String.format("%s%s%s", generModel.getPack(), StrUtil.replace(daoPack, StringPool.DOT, StringPool.SLASH), StringPool.SLASH);

        return ImmutableList.of(
                new CustomFile.Builder().fileName(CREATE_IN_VO).templatePath("/dto/create-in.java.ftl").filePath(inputDtoUrl).enableFileOverride().build(),
                new CustomFile.Builder().fileName(UPDATE_IN_VO).templatePath("/dto/update-in.java.ftl").filePath(inputDtoUrl).enableFileOverride().build(),
                new CustomFile.Builder().fileName(SEARCH_IN_VO).templatePath("/dto/search-in.java.ftl").filePath(inputDtoUrl).enableFileOverride().build(),
                new CustomFile.Builder().fileName(LIST_OUT_VO).templatePath("/dto/list-out.java.ftl").filePath(outputDtoUrl).enableFileOverride().build(),
                new CustomFile.Builder().fileName(CONVERT).templatePath("/dto/convert.java.ftl").filePath(dtoMapperUrl).enableFileOverride().build(),
                new CustomFile.Builder().fileName(DAO).templatePath("/simple/dao.java.ftl").filePath(daoUrl).enableFileOverride().build(),
                new CustomFile.Builder().fileName(VUE).templatePath("/vue/manage-element.vue.ftl").enableFileOverride().build(),
                new CustomFile.Builder().fileName(VUE_JS).templatePath("/vue/vue.js.ftl").enableFileOverride().build()
        );
    }

    /**
     * 构建自定义变量
     *
     * @param packageModel
     * @return
     */
    private static Map<String, Object> buildCustomMap(PackageModel packageModel) {
        final String inputDtoPack = String.format("%s%s%s", packageModel.getParent(), StringPool.DOT, packageModel.getInputDto());
        final String outDtoPack = String.format("%s%s%s", packageModel.getParent(), StringPool.DOT, packageModel.getOutDto());
        final String dtoMapperPack = String.format("%s%s%s", packageModel.getParent(), StringPool.DOT, packageModel.getDtoMapper());
        final String daoPack = String.format("%s%s%s", packageModel.getParent(), StringPool.DOT, packageModel.getDao());

        return ImmutableMap.of(
                "inputDtoPackage", inputDtoPack,
                "outputDtoPackage", outDtoPack,
                "dtoMapperPackage", dtoMapperPack,
                "daoPackage", daoPack
        );
    }

}
